/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package plggrupo6;

import atributosDef.Instruccion;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.StringTokenizer;
import tablaDeSimbolos.TablaDeSimbolos;

/**
 *
 * @author Prado
 */
public class Semantica {
    
    //TODO compatiblesTipo de OpsExp4!! hay una hecha pero no le vale xq el primer campo es el tipo de operacion! hay que redefinirla.
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5, Instruccion cad6){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad6);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5, Instruccion cad6, Instruccion cad7){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad6);
        cadRes.add(cad7);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad3, Instruccion cad4, Instruccion cad5, Instruccion cad6, Instruccion cad7){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad6);
        cadRes.add(cad7);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5, Instruccion cad10, ArrayList<Instruccion> cad6, Instruccion cad7){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad10);
        it = cad6.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad7);
        return cadRes;
    }
        
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        return cadRes;
    }  
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3, Instruccion cad4){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        return cadRes;
    }
    
        public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3, Instruccion cad4, Instruccion cad5, Instruccion cad6, Instruccion cad7){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad6);
        cadRes.add(cad7);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, ArrayList<Instruccion> cad3){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad3.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(Instruccion ins1, Instruccion ins2, Instruccion ins3){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        cadRes.add(ins1);
        cadRes.add(ins2);
        cadRes.add(ins3);
        return cadRes;
    }
     
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2,  ArrayList<Instruccion> cad3, Instruccion cad4){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        it = cad3.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad4);
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, ArrayList<Instruccion> cad3, Instruccion cad4, ArrayList<Instruccion> cad5){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        it = cad3.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad4);
        it = cad5.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, Instruccion cad2, Instruccion cad3, Instruccion cad4, ArrayList<Instruccion> cad5){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        it = cad5.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, Instruccion cad3){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad3);        
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1,Instruccion cad2,ArrayList<Instruccion> cad3,Instruccion cad4,Instruccion cad5,Instruccion cad6){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
            cadRes.add(it.next());
        }
        cadRes.add(cad2);
        it = cad3.iterator();
        while(it.hasNext()){
            cadRes.add(it.next());
        }
        cadRes.add(cad4);
        cadRes.add(cad5);
        cadRes.add(cad6);
        
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(Instruccion cad1,Instruccion cad2,Instruccion cad3,Instruccion cad4, Instruccion cad9, ArrayList<Instruccion> cad5,Instruccion cad6){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        
        cadRes.add(cad1);
        cadRes.add(cad2);
        cadRes.add(cad3);
        cadRes.add(cad4);
        cadRes.add(cad9);
        
        Iterator<Instruccion> it = cad5.iterator();
        while(it.hasNext()){
            cadRes.add(it.next());
        }
        
        cadRes.add(cad6);
        
        return cadRes;
    }
    
    public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, ArrayList<Instruccion> cad3, ArrayList<Instruccion> cad4){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad3.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad4.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
        public ArrayList<Instruccion> concatena(ArrayList<Instruccion> cad1, ArrayList<Instruccion> cad2, ArrayList<Instruccion> cad3, Instruccion cad4, ArrayList<Instruccion> cad5, ArrayList<Instruccion> cad6, Instruccion cad7){
        ArrayList<Instruccion> cadRes = new ArrayList<Instruccion>();
        Iterator<Instruccion> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad3.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad4);
        it = cad5.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad6.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad7);
        return cadRes;
    }
    
    //Concatena listas de etq
    public ArrayList<Integer> concatenaListasEtqs(ArrayList<Integer> cad1, ArrayList<Integer> cad2){
        ArrayList<Integer> cadRes = new ArrayList<Integer>();
        Iterator<Integer> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        return cadRes;
    }
    
    //Concatena listas de etq y una etiqueta
    public ArrayList<Integer> concatenaListasEtqs(ArrayList<Integer> cad1, ArrayList<Integer> cad2, Integer cad3){
        ArrayList<Integer> cadRes = new ArrayList<Integer>();
        Iterator<Integer> it = cad1.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        it = cad2.iterator();
        while(it.hasNext()){
           cadRes.add(it.next());
        }
        cadRes.add(cad3);
        return cadRes;
    }
    
    public ArrayList<Instruccion> parchea(ArrayList<Instruccion> cad1, ArrayList<Integer> cad2, Integer etq){
        Iterator<Integer> it = cad2.iterator();
        Iterator<Instruccion> i;
        int numIns;
        Instruccion ins;
        boolean encontrado;
        while(it.hasNext()){
            encontrado = false;
            i = cad1.iterator();
            numIns = it.next();
            while(i.hasNext() && !encontrado){
                ins = i.next();
                if(ins.getNumIns() == numIns){
                    ins.setCod(parchea(ins.getCod(), etq));
                    encontrado = true;
                }
            }
        }
        return cad1;
    }
    
    public String parchea(String cod, int etq){
        StringTokenizer token = new StringTokenizer(cod, "?");
        if(cod.contains("?")){
            return token.nextToken() + etq + token.nextToken();
        }else{
            return cod;
        }
    }
    
    public boolean[] orArray(boolean[] errores0, boolean[] errores1){
        boolean[] resultado = new boolean[11];
        for(int i=0; i< resultado.length; i++){
            resultado[i] = errores0[i] || errores1[i];
        }
        return resultado;
    }
    
    public boolean[] orArray(boolean[] errores0, boolean[] errores1, boolean[] errores2){
        boolean[] resultado = new boolean[11];
        for(int i=0; i< resultado.length; i++){
            resultado[i] = errores0[i] || errores1[i] || errores2[i];
        }
        return resultado;
    }
    
    public boolean[] orArray(boolean[] errores0, boolean[] errores1, boolean[] errores2,boolean[] errores3){
        boolean[] resultado = new boolean[11];
        for(int i=0; i< resultado.length; i++){
            resultado[i] = errores0[i] || errores1[i] || errores2[i] || errores3[i];
        }
        return resultado;
    }
    
    public boolean[] orArray(boolean[] errores0, boolean[] errores1, boolean[] errores2,boolean[] errores3,boolean[] errores4){
        boolean[] resultado = new boolean[11];
        for(int i=0; i< resultado.length; i++){
            resultado[i] = errores0[i] || errores1[i] || errores2[i] || errores3[i] || errores4[i];
        }
        return resultado;
    }
    
    public boolean compatiblesTipoValor(String tipo, String valor){
        switch(tipo){
            case "character":
                return esCharacter(valor);
            case "boolean":
                return esBoolean(valor);
            case "natural":
                return esNatural(valor);
            case "integer":
               return esInteger(valor);
            case "float": 
                return esFloat(valor);
            default: return false;
        }       
    }
    
    // metodo para ordenar los parametros de call y poder compararlos facilmente
    public ArrayList<String> ordenaTipoParametros (ArrayList<String> idsFuncion, ArrayList<String> idsParametros, ArrayList<String> tiposParametros){
        ArrayList<String> tiposOrdenados = new ArrayList<String>();
        Iterator<String> itIDsFuncion = idsFuncion.iterator();
        if (idsFuncion.size() != idsParametros.size())
            return null;
        
        while (itIDsFuncion.hasNext()){
            String idFuncion = itIDsFuncion.next();
            Iterator<String> itIDsParams = idsParametros.iterator();
            boolean encontrado = false;
            int i = 0;
            while (itIDsParams.hasNext() && !encontrado){        
                String idParam = itIDsParams.next();
                if (idParam.equals(idFuncion)){
                    encontrado = true;
                }else
                    i++;
            }
            if (!encontrado) // parametro en call erroneo 
                return null;
            else
                tiposOrdenados.add(tiposParametros.get(i));
        }
        
        return tiposOrdenados;
    }
    
    public boolean compatiblesTiposDeFuncion(TablaDeSimbolos tsh, ArrayList<String> idsFuncion, 
                ArrayList<String> tiposFuncion, ArrayList<String> identificadoresParametros, 
                ArrayList<String> tiposParametros) {
        // ordenamos los tipos de los parametros para compararlos bien:
        ArrayList<String> tiposParametrosOrdenados = ordenaTipoParametros (idsFuncion, 
                                                        identificadoresParametros, tiposParametros);
        
        if (tiposParametrosOrdenados == null)
            return false;
        
        Iterator<String> itTiposFuncion = tiposFuncion.iterator();
        Iterator<String> itTiposParam = tiposParametrosOrdenados.iterator();

        boolean compatibles = true;
        
        while (itTiposFuncion.hasNext() && itTiposParam.hasNext() && compatibles){
           String tipoFuncion = itTiposFuncion.next();
           String tipoParametros = itTiposParam.next();
           if (esTipoBasico(tipoFuncion)){
               if (esTipoBasico(tipoParametros)){
                   if (!compatiblesTipo(tipoParametros, tipoFuncion))
                        compatibles = false;
               }else{
                  /* tipoFuncion es un tipo basico, y si tipoParametros no es un 
                   * tipo basico entonces es una referencia y convertimos 
                   * tipoFuncion a formato codigo Tipo */
                  tipoParametros = tsh.dameStringTipoConID(tipoParametros);
                  if (!compatiblesStringTipo(tsh, tipoParametros, "<t: " + tipoFuncion + ", tam: 1>"))
                        compatibles = false; 
               }
           
           }else{
                tipoFuncion = tsh.dameStringTipoConID(tipoFuncion);
                tipoParametros = tsh.dameStringTipoConID(tipoParametros);

                if (!compatiblesStringTipo(tsh, tipoParametros, tipoFuncion))
                         compatibles = false; 
           }    
        }
        if (!compatibles || itTiposFuncion.hasNext() || itTiposParam.hasNext()){
            return false;
        }else{
            return true;
        }
    }
    
     private boolean esCharacter(String valor){
         return valor.contains("'");
     }
     
     private boolean esBoolean(String valor){
         return (valor.equals("true") || valor.equals("false"));
     }
     
     private boolean esNatural(String valor){
         return (!valor.contains("e") && !valor.contains("E") && !valor.contains(".") && !valor.contains("-") && !valor.contains("'"));
     }
     
     private boolean esInteger(String valor){
         String valorNatrual = valor.replace("-", "");
         return (esNatural(valorNatrual));
     }
     
     private boolean esFloat(String valor){
         return (!esBoolean(valor) && !esCharacter(valor) && !esNatural(valor) && !esInteger(valor));
     }
     
     public boolean compatiblesTipo(String tipoOperacion, String tipo1, String tipo2){
         if(tipo2 == null){
             return !tipoResultante(tipoOperacion, tipo1).equals("tError");
         }
        return !tipoResultante(tipoOperacion, tipo1, tipo2).equals("tError");
     }
     
     public boolean compatiblesTipo(String tipoAcomparar, String tipoFijado){
         if(esTipoBoolean(tipoFijado) && esTipoBoolean(tipoAcomparar)){
             return true;
         }else if(esTipoCharacter(tipoFijado) && esTipoCharacter(tipoAcomparar)){
             return true;
         }else if(tipoFijado.equals("integer") && tipoAcomparar.equals("float")){ 
             return false;
         }else if(tipoFijado.equals("natural") && tipoAcomparar.equals("integer")){ 
             return false;
         }else if(tipoFijado.equals("natural") && tipoAcomparar.equals("float")){ 
             return false;
         }else if(esTipoNumerico(tipoFijado) && esTipoNumerico(tipoAcomparar)){
             return true;
         }else{
             return false;
         }
     }
     
    public boolean compatiblesStringTipo(TablaDeSimbolos tsh, String tipoAcomparar, String tipoFijado){
        
        if(tipoAcomparar != null && tipoFijado != null){
            // compara el String tipo, para ver si dos tipos definidos son compatibles        
            StringTokenizer tokenTipo1 = new StringTokenizer(tipoAcomparar, " <:,>");
            StringTokenizer tokenTipo2 = new StringTokenizer(tipoFijado, " <:,>");
            // pasamos t
            tokenTipo1.nextToken();
            tokenTipo2.nextToken();
            // sacamos el tipo
            String t1 = tokenTipo1.nextToken();
            String t2 = tokenTipo2.nextToken();        

            if(t1.equals("array") && t2.equals("array")){
                // pasamos nElems
                tokenTipo1.nextToken();
                tokenTipo2.nextToken();
                // cogemos el valor de nElems
                int nElems1 = Integer.parseInt(tokenTipo1.nextToken());
                int nElems2 = Integer.parseInt(tokenTipo2.nextToken());
                // pasamos tBase
                tokenTipo1.nextToken();
                tokenTipo2.nextToken();

                // + 7 para pasar "tBase: " y -9 para quitar ", tam: x>"
                String tBase1 = (String) tipoAcomparar.subSequence(tipoAcomparar.indexOf("tBase") + 7, tipoAcomparar.length()-9);
                String tBase2 = (String) tipoFijado.subSequence(tipoFijado.indexOf("tBase") + 7, tipoFijado.length()-9);

                return (nElems1 == nElems2) && compatiblesStringTipo(tsh, tBase1, tBase2);

            }else if(t1.equals("tupla") && t2.equals("tupla")){
                // pasamos nElems
                tokenTipo1.nextToken();
                tokenTipo2.nextToken();
                // cogemos el valor de nElems
                int nElems1 = Integer.parseInt(tokenTipo1.nextToken());
                int nElems2 = Integer.parseInt(tokenTipo2.nextToken());
                if (nElems1 != nElems2) 
                    return false;
                
                // pasamos "<tipo: " y -10 para quitar "], tam: x>"
                String campos1 = (String) tipoAcomparar.subSequence(tipoAcomparar.indexOf("<tipo: "), tipoAcomparar.length()-10);
                String campos2 = (String) tipoFijado.subSequence(tipoFijado.indexOf("<tipo: "), tipoFijado.length()-10);
                String[] c1 = campos1.split("<tipo: ");
                String[] c2 = campos2.split("<tipo: ");
                // vamos comparando por campos:
                for (int i = 1; i <= nElems1; i++){
                    String[] camposResul1 = c1[i].split(", desp: ");
                    String[] camposResul2 = c2[i].split(", desp: ");
                    if (!compatiblesStringTipo(tsh, camposResul1[0], camposResul2[0]))
                        return false;
                }
                return true;

            // mirar si t1 es ref o t2 es ref y sacar su tipo con ID
            }else if (t1.equals("ref")){
                // pasamos id
                tokenTipo1.nextToken();

                String id = tokenTipo1.nextToken();
                String tipoRef1 = tsh.dameStringTipoConID(id);
                return compatiblesStringTipo(tsh, tipoRef1, tipoFijado);

            }else if (t2.equals("ref")){
                // pasamos id
                tokenTipo2.nextToken();

                String id = tokenTipo2.nextToken();
                String tipoRef2 = tsh.dameStringTipoConID(id);
                return compatiblesStringTipo(tsh, tipoAcomparar, tipoRef2);

            }else{
                // t1 y t2 son tipos basicos: t1->tipoAcomparar t2->tipoFijado
                return compatiblesTipo(t1, t2);
            }
            
        }else
            return false;
    }
    
     public String tipoResultante(String tipoOperacion, String tipo1, String tipo2){
         switch(tipoOperacion){
             case "<": if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)))return "boolean";
                     else return "tError";
             case ">": if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)))return "boolean";
                     else return "tError";
             case "<=": if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)))return "boolean";
                     else return "tError";
             case ">=": if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)))return "boolean";
                     else return "tError";
             case "==": if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)))return "boolean";
                     else return "tError";
             case "!=": 
                 if(compatiblesTipo(tipo1,tipo2) || (esTipoNumerico(tipo1) && esTipoNumerico(tipo2))){
                     return "boolean";
                 }else{
                     return "tError";
                 }
             case "and":
             case "or":
             case "not":
                 if(esTipoBoolean(tipo1) && esTipoBoolean(tipo2)){ 
                     return "boolean";
                 }else{
                     return "tError";
                 }
             case "+":
             case "-":
             case "*":
             case "/":
             case "%":
                 return tipoDominante(tipo1, tipo2);
             case "<<":
             case ">>":
                 if(esNatural(tipo1) && esNatural(tipo2)){
                     return "natural";
                 }else{
                     return "tError";
                 }
             default: return "tError";
         }
     }
     
     public String tipoResultante(String tipoOperacion, String tipo){
         switch(tipoOperacion){
             case "not":
                 if(esTipoBoolean(tipo)){
                     return tipo;
                 }else{
                     return "tError";
                 }
             case "-":
                 if(esTipoNumerico(tipo)){
                     if(esNatural(tipo)){
                         return "integer";
                     }else{
                         return tipo;
                     }
                 }else{
                     return "tError";
                 }
             default : return "tError";
         }
     }
     
     public String tipoDominante(String tipo1, String tipo2){
         if(tipo1.equals("tError") || tipo2.equals("tError")){
             return "tError";
         }else if(tipo1.equals(tipo2)){
             return tipo1;
         }else if (esTipoNumerico(tipo1) && esTipoNumerico(tipo2)){
             if(tipo1.equals("float") || tipo2.equals("float")){
                 return "float";
             }else if(tipo1.equals("integer") || tipo2.equals("integer")){
                 return "integer";
             }else{
                 return "natural";
             }
         }else if(esTipoBoolean(tipo1) && esTipoBoolean(tipo2)){
             return "boolean";
         }else if(esTipoCharacter(tipo1) && esTipoCharacter(tipo2)){
             return "character";
         }else{
             return "tError";
         }
     }
     
     public boolean esTipoNumerico(String tipo){
         switch(tipo){
             case "natural":
             case "integer":
             case "float":
                 return true;
             default : return false;
         }
     }
     
     public boolean esTipoBoolean(String tipo){
         return tipo.equals("boolean");
     }
     
     public boolean esTipoCharacter(String tipo){
         return tipo.contains("'");
     }
     
     public String dameTipo(String valor){
         if(esCharacter(valor)){
             return "character";
         }else if (esBoolean(valor)){
             return "boolean";
         }else if(esNatural(valor)){
             return "natural";
         }else if(esInteger(valor)){
             return "integer";
         }else if(esFloat(valor)){
             return "float";
         }else{
             return "tError";
         }
     }
     
     public String casting(String tipoCast, String tipoACast){
         if(tipoCast.equals("float")){
            if(esTipoNumerico(tipoACast) || tipoACast.equals("character"))
                            return "float";
                    else
                            return "tError";
            }else if(tipoCast.equals("integer")){
                    if(esTipoNumerico(tipoACast) || tipoACast.equals("character"))
                            return "integer";
                    else
                            return "tError";
            }else if(tipoCast.equals("natural")){
                    if(tipoACast.equals("natural") || tipoACast.equals("character"))
                            return "natural";
                    else
                            return "tError";
            }else if(tipoCast.equals("character")){
                    if(tipoACast.equals("natural") || tipoACast.equals("character"))
                            return "character";
                    else
                            return "tError";
            }else
                    return "tError";
     }
     
     public boolean esTipoBasico(String tipo){
         switch(tipo){
             case "character":
             case "boolean":
             case "integer":
             case "float":
             case "natural":
                 return true;
             default: return false;
         }
    }
         
    public ArrayList<Instruccion> codPrologo(int etqPrologo,int tam){
        ArrayList<Instruccion> codPrologo = new ArrayList<Instruccion>();

        Instruccion instruccion;   
        etqPrologo++;
        instruccion = new Instruccion("apila_dir(0)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("apila(2)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("sumar",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("apila_dir(1)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("desapila_ind",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("apila_dir(0)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("apila(3)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("sumar",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("desapila_dir(1)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        tam = tam + 2;
        instruccion = new Instruccion("apila(" + Integer.toString(tam) + ")",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("apila_dir(0)",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("sumar",etqPrologo);
        codPrologo.add(instruccion);
        
        etqPrologo++;
        instruccion = new Instruccion("desapila_dir(0)",etqPrologo);
        codPrologo.add(instruccion);
        
        return codPrologo;
    }


    public ArrayList<Instruccion> codEpilogo(int etqEpilogo,int tam){
       ArrayList<Instruccion> codEpilogo = new ArrayList<Instruccion>();

       Instruccion instruccion;

       etqEpilogo++;
       instruccion = new Instruccion("apila_dir(0)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       tam = tam + 2;
       instruccion = new Instruccion("apila(" + Integer.toString(tam) + ")",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("restar",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("desapila_dir(0)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("apila_dir(0)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("apila(2)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("sumar",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("apila_ind",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("desapila_dir(1)",etqEpilogo);
       codEpilogo.add(instruccion);
       
       etqEpilogo++;
       instruccion = new Instruccion("apila_dir(0)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("apila(1)",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("sumar",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("apila_ind",etqEpilogo);
       codEpilogo.add(instruccion);

       etqEpilogo++;
       instruccion = new Instruccion("ir_ind",etqEpilogo);
       codEpilogo.add(instruccion);
       
       return codEpilogo;
    }
     
    public String valorDe(String cad){
        String tipo = dameTipo(cad);
        Float valor;
        if(tipo.equals("boolean")){ 
            if(cad.equals("true")){
                valor = Float.parseFloat("1.0");
            }else{
                valor = Float.parseFloat("0.0");
            }
        }else if(tipo.equals("character")){
            char c;
            int a = cad.length();
            if(cad.length() == 4){
                c = cad.charAt(2);
                if(c == 'n'){
                    c = '\n';
                }else if(c == 't'){
                    c = '\t';
                }
            }else{
                c = cad.charAt(1);
            }
            float valaux = c;
            valor = valaux;
        }else if(tipo.equals("natural") || tipo.equals("integer")){
            valor = Float.parseFloat(cad+".0");
        }else{
            valor = Float.parseFloat(cad);
        }
        return valor.toString();
    }
}
 